package com.dc.util;

import com.dc.common.DateUtil;
import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.springframework.util.CollectionUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

public class ExcelUtil {
    /**
     * 导出Excel
     * @param sheetName sheet名称
     * @param title 标题
     * @param values 内容
     * @param wb HSSFWorkbook对象
     * @return
     */
    public static HSSFWorkbook getHSSFWorkbook(String sheetName, String []title, String [][]values, HSSFWorkbook wb){

        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        if(wb == null){
            wb = new HSSFWorkbook();
        }

        // 第二步，在workbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName);

        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        HSSFRow row = sheet.createRow(0);

        // 第四步，创建单元格，并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        //style.setAlignment();
        //style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式

        style.setBorderBottom((BorderStyle.THIN));//下边框
        style.setBorderLeft(BorderStyle.THIN);//左边框
        style.setBorderRight(BorderStyle.THIN);//右边框
        style.setBorderTop(BorderStyle.THIN); //上边框


        //声明列对象
        HSSFCell cell = null;

        //创建标题
        for(int i=0;i<title.length;i++){
            cell = row.createCell(i);
            cell.setCellValue(title[i]);
            cell.setCellStyle(style);
        }

        //声明列对象
        HSSFCell cellContent = null;
        //创建内容
        for(int i=0;i<values.length;i++){

            row = sheet.createRow(i + 1);
            for(int j=0;j<values[i].length;j++){
                //将内容按顺序赋给对应的列对象
                sheet.autoSizeColumn(j);
                cellContent = row.createCell(j);
                cellContent.setCellValue(values[i][j]);
                cellContent.setCellStyle(style);
            }
        }
        return wb;
    }


    /**
     * 解析数据集合，生成Excel<p>
     * 注：根据反射解析对象集合，需要集合中所有元素的对象类型一致
     * @param sheetName Excel中的sheet名称
     * @param list 需要导出的数据对象集合
     * @return
     */
    public static HSSFWorkbook getHSSFWorkbook(String sheetName, List<? extends Object> list) {
        if (CollectionUtils.isEmpty(list)) {
            throw new NullPointerException("参数list不能为空");
        }
        if (StringUtils.isBlank(sheetName)) {
            sheetName = "sheet1";
        }

        // 需要导出的属性字段集合
        List<Field> fieldList = new ArrayList<>();
        // 表头集合
        List<String> titleList = new ArrayList<>();
        // 获取对象属性值
        Field[] fields = list.get(0).getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            // 获取属性的@ApiModelProperty注解对象
            ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
            if (apiModelProperty == null || apiModelProperty.hidden()) {
                // 没有配置注解、或 隐藏的属性，则跳过
                continue;
            }
            // 获取value值为表头名称
            String title = apiModelProperty.value();
            if (StringUtils.isBlank(title)) {
                // value值为空的，则取属性字段名为表头
                title = field.getName();
            }
            titleList.add(title);

            // 选择需要的属性字段
            fieldList.add(field);
        }
        List<List<String>> rowList = getRowList(list, fieldList);

        // 第一步，创建一个HSSFWorkbook，对应一个Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();
        // 第二步，在workbook中添加一个sheet,对应Excel文件中的sheet
        HSSFSheet sheet = wb.createSheet(sheetName);
        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
        HSSFRow row = sheet.createRow(0);
        // 第四步，创建单元格，并设置值表头 设置表头居中
        HSSFCellStyle style = wb.createCellStyle();
        style.setBorderBottom((BorderStyle.THIN));//下边框
        style.setBorderLeft(BorderStyle.THIN);//左边框
        style.setBorderRight(BorderStyle.THIN);//右边框
        style.setBorderTop(BorderStyle.THIN); //上边框

        // 声明列对象
        HSSFCell cell = null;
        // 创建标题
        for (int i = 0; i < titleList.size(); i++) {
            cell = row.createCell(i);
            cell.setCellValue(titleList.get(i));
            cell.setCellStyle(style);
        }
        // 声明列对象
        HSSFCell cellContent = null;
        // 创建内容
        for (int i = 0; i < rowList.size(); i++) {
            row = sheet.createRow(i + 1);
            List<String> rowValueList = rowList.get(i);
            for (int j = 0; j < rowValueList.size(); j++) {
                // 将内容按顺序赋给对应的列对象
                sheet.autoSizeColumn(j);
                cellContent = row.createCell(j);
                cellContent.setCellValue(rowValueList.get(j));
                cellContent.setCellStyle(style);
            }
        }
        return wb;
    }


    /**
     * 根据反射解析list集合，转换为Excel rowList
     * @param list 需要解析的集合
     * @param fieldList 集合对象类型的属性字段集合
     * @return
     */
    private static List<List<String>> getRowList(List<? extends Object> list, List<Field> fieldList) {
        // 行集合
        List<List<String>> rowList = new ArrayList<>();
        // 读取属性值的get方法集合，key为属性名称
        Map<String, Method> methodMap = getGetMethodMap(list.get(0).getClass(), fieldList);

        // 解析导出内容集合
        for (Object obj : list) {
            List<String> row = new ArrayList<>();
            for (Field field : fieldList) {
                field.setAccessible(true);
                Object value = null;
                try {
                    // 通过get方法读取属性值，这样可以支持get方法自定义返回值
                    Method readMethod = methodMap.get(field.getName());
                    if (readMethod != null) {
                        value = readMethod.invoke(obj);
                    }
                } catch (Exception e) {

                }
                if (value == null) {
                    row.add("");
                    continue;
                }
                if (value instanceof Date) {
                    // 日期统一使用yyyy-MM-dd HH:mm:ss格式
                    row.add(DateUtil.parseDateToStr((Date) value, DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS));
                } else {
                    // 其它类型统一转换成字符串
                    row.add(String.valueOf(value));
                }
            }
            rowList.add(row);
        }
        return rowList;
    }


    /**
     * 获取对象属性的get方法集合
     * @param cls 对象类型
     * @param fieldList 属性集合
     * @return get方法集合
     */
    private static Map<String, Method> getGetMethodMap(Class cls, List<Field> fieldList) {
        Map<String, Method> methodMap = new HashMap<>();
        for (Field field : fieldList) {
            field.setAccessible(true);
            try {
                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), cls);
                Method readMethod = pd.getReadMethod();
                methodMap.put(field.getName(), readMethod);
            } catch (Exception e) {

            }
        }
        return methodMap;
    }

}
